package com.xiaomaoguai.fcp.YND.test;

import com.xiaomaoguai.fcp.kepler.utils.Base64Utils;
import lombok.extern.log4j.Log4j;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.Key;

/**
 * @author wangchaowu
 * @date 2018年8月7日 下午12:45:25
 */
@Log4j
public class DesFileUtils {

	/**
	 * 加密解密的key
	 */
	private Key mKey;

	/**
	 * 解密的密码
	 */
	private Cipher mDecryptCipher;

	/**
	 * 加密的密码
	 */
	private Cipher mEncryptCipher;

	public DesFileUtils(String key) throws Exception {
		synchronized (this) {
			initKey(key);
			initCipher();
		}
	}

	/**
	 * 创建一个加密解密的key
	 *
	 * @param keyRule
	 */
	private void initKey(String keyRule) {
		byte[] keyByte = keyRule.getBytes();
		// 创建一个空的八位数组,默认情况下为0
		byte[] byteTemp = new byte[8];
		// 将用户指定的规则转换成八位数组
		for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {
			byteTemp[i] = keyByte[i];
		}
		mKey = new SecretKeySpec(byteTemp, "DES");
	}

	/***
	 * 初始化加载密码
	 *
	 * @throws Exception
	 */
	private void initCipher() throws Exception {
		mEncryptCipher = Cipher.getInstance("DES");
		mEncryptCipher.init(Cipher.ENCRYPT_MODE, mKey);
		mDecryptCipher = Cipher.getInstance("DES");
		mDecryptCipher.init(Cipher.DECRYPT_MODE, mKey);
	}

	/**
	 * 加密文件
	 *
	 * @param filePath 需要加密的文件路径
	 * @param savePath 加密后保存的位置
	 */
	public void encryptFile(String filePath, String savePath) {
		FileInputStream in = null;
		CipherInputStream cin = null;
		OutputStream os = null;
		try {
			in = new FileInputStream(filePath);
			cin = new CipherInputStream(in, mEncryptCipher);
			os = new FileOutputStream(savePath);
			byte[] bytes = new byte[1024];
			int len = -1;
			while ((len = cin.read(bytes)) > 0) {
				os.write(bytes, 0, len);
				os.flush();
			}
		} catch (Exception e) {
			log.error("文件加密失败,filePath=" + filePath, e);
			throw new RuntimeException("文件加密失败");
		} finally {
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					log.error("输入文件流关闭失败", e);
				}
			}
			if (null != cin) {
				try {
					cin.close();
				} catch (IOException e) {
					log.error("加密输入文件流关闭失败", e);
				}

			}
			if (null != os) {
				try {
					os.close();
				} catch (IOException e) {
					log.error("输出文件流关闭失败", e);
				}

			}
		}
	}

	/**
	 * 解密文件
	 *
	 * @param filePath
	 * @param outPath
	 */
	public void decryptFile(String filePath, String outPath) {
		FileInputStream in = null;
		CipherInputStream cin = null;
		OutputStream os = null;
		try {
			in = new FileInputStream(filePath);
			cin = new CipherInputStream(in, mDecryptCipher);
			os = new FileOutputStream(outPath);
			byte[] buffer = new byte[1024];
			int i;
			while ((i = cin.read(buffer)) != -1) {
				os.write(buffer, 0, i);
			}
		} catch (Exception e) {
			log.error("文件解密失败,filePath=" + filePath, e);
			throw new RuntimeException("文件解密失败");
		} finally {
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					log.error("输入文件流关闭失败", e);
				}
			}
			if (null != cin) {
				try {
					cin.close();
				} catch (IOException e) {
					log.error("加密输入文件流关闭失败", e);
				}

			}
			if (null != os) {
				try {
					os.close();
				} catch (IOException e) {
					log.error("输出文件流关闭失败", e);
				}

			}
		}
	}

	/**
	 * @param publicKey
	 * @param sourceFilepath
	 * @param localFilePath  设定文件 @return void 返回类型 @throws
	 * @Title: encryptFile
	 * @Description: 加密文件
	 */
	public static void encryptFile(String publicKey, String sourceFilepath, String localFilePath) {
		FileOutputStream fos = null;
		try {
			byte[] data = Base64Utils.fileToByte(sourceFilepath);
			byte[] desData = DesUtil.encryptBytes(data, publicKey.getBytes());
			fos = new FileOutputStream(new File(localFilePath));
			fos.write(desData);
		} catch (Exception e) {
			log.error("文件加密失败,zaFilePath:" + sourceFilepath, e);
			throw new RuntimeException("文件加密失败");
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					log.error("输入文件流关闭失败", e);
				}
			}
		}
	}

	/**
	 * @param sourceFilePath
	 * @param localFilePath  设定文件 @return void 返回类型 @throws
	 * @Title: decryptFileFromPartner
	 * @Description: 解密合作方的文件
	 */
	public static void decryptFile(String publicKey, String sourceFilePath, String localFilePath) {
		FileOutputStream fos = null;
		try {
			byte[] data = Base64Utils.fileToByte(sourceFilePath);
			byte[] desData = DesUtil.decryptBytes(data, publicKey.getBytes());
			fos = new FileOutputStream(new File(localFilePath));
			fos.write(desData);
		} catch (Exception e) {
			log.error("文件解密失败,filePath:" + sourceFilePath, e);
			throw new RuntimeException("文件解密失败");
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					log.error("输入文件流关闭失败", e);
				}
			}
		}
	}

}
